package com.yanqu.road.server.gameplayer.module.activity.ppl;

import com.yanqu.road.entity.activity.ppl.BallEliminate;
import com.yanqu.road.entity.activity.ppl.PplDrumInfo;
import com.yanqu.road.entity.activity.ppl.PplDrumReward;
import com.yanqu.road.entity.activity.ppl.PplGoods;
import com.yanqu.road.entity.activity.ppl.PplLine;
import com.yanqu.road.entity.activity.ppl.PplShootResult;
import com.yanqu.road.entity.activity.ppl.PplUserData;
import com.yanqu.road.entity.bag.UseGoodsResult;
import com.yanqu.road.entity.enums.eGamePlayerEventType;
import com.yanqu.road.entity.enums.eLogMoneyType;
import com.yanqu.road.entity.enums.eMailType;
import com.yanqu.road.entity.enums.eSystemId;
import com.yanqu.road.entity.player.UserBeauty;
import com.yanqu.road.logic.bussiness.activity.PplBussiness;
import com.yanqu.road.server.pb.PplPb;
import com.yanqu.road.pb.activity.PplProto;
import com.yanqu.road.server.gameplayer.GamePlayer;
import com.yanqu.road.server.gameplayer.module.base.GeneralModule;
import com.yanqu.road.server.gameplayer.module.player.BagModule;
import com.yanqu.road.server.gameplayer.module.player.BeautyModule;
import com.yanqu.road.server.gameplayer.module.player.CurrencyModule;
import com.yanqu.road.server.logic.mail.MailManager;
import com.yanqu.road.server.manger.MultipleLanguageMgr;
import com.yanqu.road.server.manger.activity.ppl.PplMgr;
import com.yanqu.road.server.manger.config.SystemOpenMgr;
import com.yanqu.road.server.protocol.ClientProtocol;
import com.yanqu.road.server.protocol.GameErrorCode;
import com.yanqu.road.utils.LocalDateTimeHelper;
import com.yanqu.road.utils.property.Property;
import com.yanqu.road.utils.property.PropertyHelper;
import com.yanqu.road.utils.string.StringUtils;

import java.math.BigInteger;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Random;

/**
 * 泡泡龙用户模块
 */
public class PplModule extends GeneralModule {

    private PplUserData userData;

    private Random random = new Random();

    public PplModule(GamePlayer player) {
        super(player);
    }

    @Override
    public boolean loadData() {
        int activityId = PplMgr.getShowTimeActivityId();
        if (activityId != 0 && SystemOpenMgr.systemOpen(player, eSystemId.Ppl.getValue())) {
            userData = PplBussiness.getPplUserData(player.getUserId(), activityId);
            if (userData == null) {
                initUserData();
            }
        }
        return true;
    }

    @Override
    public boolean afterLoadData() {
        return true;
    }

    @Override
    public boolean saveData() {
        if (userData != null) {
            if (userData.isInsertOption()) {
                PplBussiness.addPplUserData(userData);
            } else if (userData.isUpdateOption()) {
                PplBussiness.updatePplUserData(userData);
            }
        }
        return true;
    }

    @Override
    public void afterLogin() {
        dailyReset();
        syncEnergy();
    }

    public synchronized void dailyReset() {
        if (userData == null) {
            return;
        }
        long zeroTimeTimeStamp = LocalDateTimeHelper.getZeroTimeTimeStamp();
        long scoreResetTime = userData.getScoreResetTime();
        if (scoreResetTime < zeroTimeTimeStamp) {
            userData.setScoreResetTime(zeroTimeTimeStamp);
            userData.setTodayScore(0);
            syncUserData();
        }
    }

    public void syncUserData() {
        PplProto.PplUserDataMsg.Builder msg = PplPb.parsePplUserDataMsg(userData);
        player.sendPacket(ClientProtocol.U_ACTIVITY_PPL_USERDATA_SYNC, msg);
    }

    public synchronized void initUserData() {
        if (userData == null || userData.getActivityId() != PplMgr.getShowTimeActivityId()) {
            PplUserData tmpUserData = new PplUserData();
            tmpUserData.setUserId(player.getUserId());
            tmpUserData.setActivityId(PplMgr.getShowTimeActivityId());
            tmpUserData.setBeautyId(0);
            tmpUserData.setEnergy(PplMgr.MAX_ENERGY);
            tmpUserData.setLastRecoveryTime(System.currentTimeMillis());
            tmpUserData.setDrumList(new ArrayList<>());
            tmpUserData.setTodayScore(0);
            tmpUserData.setScoreResetTime(LocalDateTimeHelper.getZeroTimeTimeStamp());
            PplMgr.autoAddDrum(tmpUserData);

            // 1倍数据
            tmpUserData.changeMulti(1);
            tmpUserData.setHeadColor(random.nextInt(PplMgr.TOTAL_COLOR_COUNT) + 1);
            tmpUserData.setCurColor(3);
            tmpUserData.setCurMaxY(PplMgr.INIT_Y);
            tmpUserData.setPplLineList(new ArrayList<>());
            PplMgr.autoAddLine(tmpUserData, random);
            tmpUserData.saveMultiData();
            // 4倍数据
            tmpUserData.changeMulti(2);
            tmpUserData.setHeadColor(random.nextInt(PplMgr.TOTAL_COLOR_COUNT) + 1);
            tmpUserData.setCurColor(3);
            tmpUserData.setCurMaxY(PplMgr.INIT_Y);
            tmpUserData.setPplLineList(new ArrayList<>());
            PplMgr.autoAddLine(tmpUserData, random);
            tmpUserData.saveMultiData();
            // 16倍数据
            tmpUserData.changeMulti(3);
            tmpUserData.setHeadColor(random.nextInt(PplMgr.TOTAL_COLOR_COUNT) + 1);
            tmpUserData.setCurColor(3);
            tmpUserData.setCurMaxY(PplMgr.INIT_Y);
            tmpUserData.setPplLineList(new ArrayList<>());
            PplMgr.autoAddLine(tmpUserData, random);
            tmpUserData.saveMultiData();

            tmpUserData.setInsertOption();
            userData = tmpUserData;
        }
    }

    /**
     * 是否选择美女
     */
    public boolean isBeautyChosen() {
        return userData != null && userData.getBeautyId() > 0;
    }

    /**
     * 体力是否足够
     */
    public boolean isEnergyEnough(int count) {
        return userData != null && userData.getEnergy() >= count;
    }

    /**
     * 发射到屏幕外
     */
    public int shootBallOutScreen() {
        int needEnergy = userData.getCurMultiType() == 3 ? 16
                : userData.getCurMultiType() == 2 ? 4
                : 1;
        // 体力是否够
        if (!isEnergyEnough(needEnergy)) {
            return GameErrorCode.E_ACTIVITY_PPL_ENERGY_NO_ENOUGH;
        }
        // 变颜色
        userData.setCurColor(random.nextInt(PplMgr.TOTAL_COLOR_COUNT) + 1);
        // 扣体力
        reduceEnergy(needEnergy);
        return 0;
    }

    /**
     * 发射球
     */
    public PplShootResult shootBall(int x, int y) {
        int needEnergy = userData.getCurMultiType() == 3 ? 16
                : userData.getCurMultiType() == 2 ? 4
                : 1;
        // 体力是否够
        if (!isEnergyEnough(needEnergy)) {
            PplShootResult result = new PplShootResult();
            result.setRet(GameErrorCode.E_ACTIVITY_PPL_ENERGY_NO_ENOUGH);
            return result;
        }
        // 消除
        PplShootResult result = PplMgr.eliminateBalls(userData, x, y, random);
        if (result.getRet() == 0) {
            userData.setCurColor(random.nextInt(PplMgr.TOTAL_COLOR_COUNT) + 1);
            // 领取宝箱奖励
            getBoxRewards(result.getEliminateList());
            // 领取鼓奖励（并设置到result）
            result.setDrumRewardList(getDrumFullReward());
            // 领取积分奖励
            addEliminateScore(result.getEliminateList());
            player.notifyListener(eGamePlayerEventType.PplScoreRank.getValue(), userData.getScore());
            player.notifyListener(eGamePlayerEventType.PplScoreCrossRank.getValue(), userData.getScore());

            // 扣体力
            reduceEnergy(needEnergy);
        }
        return result;
    }

    /**
     * 选择美女
     */
    public int chooseBeauty(int beautyId) {
        List<Integer> beautyIdList = new ArrayList<>();
        beautyIdList.add(beautyId);
        BeautyModule beautyModule = player.getModule(BeautyModule.class);
        if (!beautyModule.checkBeautyList(beautyIdList)) {
            return GameErrorCode.E_ACTIVITY_PPL_BEAUTY_NO_EXIST;
        }
        userData.setBeautyId(beautyId);
        return 0;
    }

    /**
     * 领取鼓集满的奖励
     */
    public List<PplDrumReward> getDrumFullReward() {
        List<PplDrumReward> drumRewardList = new ArrayList<>();
        Property property = new Property();

        List<Integer> userDrumList = userData.getDrumList();
        List<PplDrumInfo> drumInfoList = PplMgr.getDrumInfoList();
        for (int i = 0; i < userDrumList.size() && i < drumInfoList.size(); i++) {
            Integer curCount = userDrumList.get(i);
            PplDrumInfo drumInfo = drumInfoList.get(i);
            if (curCount >= drumInfo.getNeedBallCount()) {
                int times = curCount / drumInfo.getNeedBallCount(); // 兼容一次性领取一个鼓的多次集满奖励
                Property tmpProperty = PropertyHelper.parseStringToProperty(drumInfo.getFullReward());
                tmpProperty.rideProperty(times);

                PplDrumReward drumReward = new PplDrumReward();
                drumReward.setIndex(i);
                drumReward.setReward(PropertyHelper.parsePropertyToString(tmpProperty));
                drumRewardList.add(drumReward);

                userDrumList.set(i, curCount - drumInfo.getNeedBallCount() * times);
                property.addProperty(tmpProperty);
            }
        }

        userData.setUpdateOption();
        player.getModule(CurrencyModule.class).addCurrency(property, eLogMoneyType.Ppl, eLogMoneyType.PplFullDrumReward);
        return drumRewardList;
    }

    /**
     * 获取玩家数据
     */
    public PplUserData getUserData() {
        return this.userData;
    }

    /**
     * 领取掉落的宝箱奖励
     */
    public void getBoxRewards(List<BallEliminate> eliminateList) {
        Property property = new Property();
        for (BallEliminate ball : eliminateList) {
            if (ball.getColor() == -1) {
                String reward = PplMgr.getBoxRandomReward();
                Property tmpProp = PropertyHelper.parseStringToProperty(reward);
                // 多倍判断
                if (userData.getCurMultiType() == 2) {
                    tmpProp.rideProperty(4);
                } else if (userData.getCurMultiType() == 3) {
                    tmpProp.rideProperty(16);
                }
                ball.setReward(PropertyHelper.parsePropertyToString(tmpProp));
                property.addProperty(tmpProp);
            }
        }
        player.getModule(CurrencyModule.class).addCurrency(property, eLogMoneyType.Ppl, eLogMoneyType.PplBoxReward);
    }

    /**
     * 添加消除球的积分
     */
    public synchronized void addEliminateScore(List<BallEliminate> eliminateList) {
        List<PplDrumInfo> drumInfoList = PplMgr.getDrumInfoList();
        int totalScore = 0;
        for (BallEliminate ball : eliminateList) {
            if (ball.getColor() <= 0) {
                // 宝箱没积分
                continue;
            }
            PplDrumInfo drumInfo = drumInfoList.get(ball.getDrumIndex());
            totalScore += drumInfo.getOneBallScore();
        }

        // 多倍判断
        if (userData.getCurMultiType() == 2) {
            totalScore *= 4;
        } else if (userData.getCurMultiType() == 3) {
            totalScore *= 16;
        }

        userData.setScore(totalScore + userData.getScore());
        userData.setTodayScore(totalScore + userData.getTodayScore());

        Property property = new Property();
        property.addProperty(PplMgr.PPL_SCORE_GOODS_ID, BigInteger.valueOf(totalScore));
        player.getModule(CurrencyModule.class).addCurrency(property, eLogMoneyType.Ppl, eLogMoneyType.PplEliminateScore);
    }

    /**
     * 使用活动道具
     */
    public UseGoodsResult usePplGoods(int goodsId, int count) {
        UseGoodsResult result = new UseGoodsResult();

        PplGoods pplGoods = PplMgr.getPplGoodsMap().get(goodsId);
        if (pplGoods == null) {
            result.setRet(GameErrorCode.E_ACTIVITY_PPL_ITEM_USE_ERROR);
            return result;
        }

        Property property = new Property();
        property.addProperty(goodsId, BigInteger.valueOf(count));
        CurrencyModule currencyModule = player.getModule(CurrencyModule.class);
        if (pplGoods.getType() == 1) {
            // 恢复体力道具
            if (!PplMgr.isActivityInTime()) {
                result.setRet(GameErrorCode.E_ACTIVITY_PPL_NO_IN_TIME);
                return result;
            }
            if (!currencyModule.removeCurrency(property, eLogMoneyType.Ppl, eLogMoneyType.PplUseGoods)) {
                result.setRet(GameErrorCode.E_BAG_ITEM_NO_ENOUGH);
                return result;
            }
            addEnergy(pplGoods.getAddEnergy() * count);
        } else if (pplGoods.getType() == 2) {
            // 琴谱
            if (count != 1) {
                result.setRet(GameErrorCode.E_ACTIVITY_PPL_ITEM_USE_ERROR);
                return result;
            }
            BeautyModule beautyModule = player.getModule(BeautyModule.class);
            UserBeauty userBeauty = beautyModule.getUserBeauty(userData.getBeautyId());
            if (userBeauty == null) {
                result.setRet(GameErrorCode.E_ACTIVITY_PPL_BEAUTY_NO_EXIST);
                return result;
            }
            if (!currencyModule.removeCurrency(property, eLogMoneyType.Ppl, eLogMoneyType.PplUseGoods)) {
                result.setRet(GameErrorCode.E_BAG_ITEM_NO_ENOUGH);
                return result;
            }
            beautyModule.addGlamour(userBeauty, pplGoods.getAddGlamour(), eLogMoneyType.Ppl.getValue(), eLogMoneyType.PplUseGoods.getValue());
            beautyModule.syncUserBeauty(userBeauty);
            currencyModule.addCurrency(PropertyHelper.parseStringToProperty(pplGoods.getReward()), eLogMoneyType.Ppl, eLogMoneyType.PplUseGoods);
            result.setReward(pplGoods.getReward());
        } else {
            result.setRet(GameErrorCode.E_ACTIVITY_PPL_ITEM_USE_ERROR);
            return result;
        }
        return result;
    }

    /**
     * 领奖期自动使用活动道具
     */
    public void autoUseGoods() {
        Property reward = new Property();
        // 获取魅力最高的美女
        UserBeauty userBeauty = null;
        int maxGlamour = -1;
        BeautyModule beautyModule = player.getModule(BeautyModule.class);
        Map<Integer, UserBeauty> beautyMap = beautyModule.getBeautyMap();
        for (UserBeauty tmpBeauty : beautyMap.values()) {
            if (maxGlamour < tmpBeauty.getGlamour()) {
                maxGlamour = tmpBeauty.getGlamour();
                userBeauty = tmpBeauty;
            }
        }
        if (userBeauty == null) {
            log.error("PplModule autoUseGoods error! Can not find UserBeauty!");
            return;
        }
        // 扣减道具、加魅力值
        int totalAddGlamour = 0;
        BagModule bagModule = player.getModule(BagModule.class);
        CurrencyModule currencyModule = player.getModule(CurrencyModule.class);
        for (PplGoods pplGoods : PplMgr.getPplGoodsMap().values()) {
            if (pplGoods.getType() == 2) {
                int count = (int) bagModule.getUserBagItemCount(pplGoods.getGoodsId());
                Property consume = new Property(pplGoods.getGoodsId(), BigInteger.valueOf(count));
                currencyModule.removeCurrency(consume, eLogMoneyType.Ppl, eLogMoneyType.PplAutoUseGoods);

                int addGlamour = count * pplGoods.getAddGlamour();
                beautyModule.addGlamour(userBeauty, addGlamour, eLogMoneyType.Ppl.getValue(), eLogMoneyType.PplAutoUseGoods.getValue());
                beautyModule.syncUserBeauty(userBeauty);
                totalAddGlamour += addGlamour;

                Property tmpReward = PropertyHelper.parseStringToProperty(pplGoods.getReward());
                tmpReward.rideProperty(count);
                reward.addProperty(tmpReward);
            }
        }
        // 邮件发奖
        String language = player.getLanguage();
        String beautyName = beautyModule.getBeautyName(userBeauty.getBeautyId(), language);
        String title = MultipleLanguageMgr.getContent(MailManager.ACTIVITY_PPL_AUTO_USE_GOODS_TITLE, language);
        String content = StringUtils.format(MultipleLanguageMgr.getContent(MailManager.ACTIVITY_PPL_AUTO_USE_GOODS_CONTENT, language),
                beautyName, totalAddGlamour);
        MailManager.sendMail(player.getUserId(), eMailType.SYSTEM.getValue(), PropertyHelper.parsePropertyToString(reward), title, content);
    }

    /**
     * 检查体力恢复
     */
    public void checkEnergyRecovery() {
        if (userData == null) {
            return;
        }
        int energy = userData.getEnergy();
        // 满了就不用恢复
        if (energy >= PplMgr.MAX_ENERGY) {
            return;
        }
        long lastRecoveryTime = userData.getLastRecoveryTime();
        long nowTime = System.currentTimeMillis();
        long subTime = nowTime - lastRecoveryTime;
        long recoveryTime = PplMgr.ENERGY_RECOVERY_TIME_SECOND * 1000;
        // 是否达到恢复时间
        if (subTime >= recoveryTime) {
            int times = (int) (subTime / recoveryTime);
            int tmpEnergy = userData.getEnergy() + times * PplMgr.ENERGY_RECOVERY_COUNT;
            long tmpTime = userData.getLastRecoveryTime() + times * recoveryTime;
            // 不能超过上限
            if (tmpEnergy > PplMgr.MAX_ENERGY) {
                tmpEnergy = PplMgr.MAX_ENERGY;
                tmpTime = nowTime;
            }
            userData.setEnergy(tmpEnergy);
            userData.setLastRecoveryTime(tmpTime);
            syncEnergy();
        }
    }

    /**
     * 减少体力
     */
    public boolean reduceEnergy(int count) {
        int energy = userData.getEnergy();
        if (energy < count) {
            return false;
        }
        boolean energyFullBefore = energy >= PplMgr.MAX_ENERGY;
        userData.setEnergy(energy - count);
        energy = userData.getEnergy();
        boolean energyFullAfter = energy >= PplMgr.MAX_ENERGY;
        if (energyFullBefore && !energyFullAfter) {
            userData.setLastRecoveryTime(System.currentTimeMillis());
        }
        syncEnergy();
        return true;
    }

    /**
     * 增加体力
     */
    private void addEnergy(int count) {
        userData.setEnergy(userData.getEnergy() + count);
        syncEnergy();
    }

    /**
     * 同步体力值
     */
    public void syncEnergy() {
        if (userData == null) {
            return;
        }
        PplProto.syncPplEnergyMsg.Builder builder = PplProto.syncPplEnergyMsg.newBuilder();
        builder.setEnergy(userData.getEnergy());
        builder.setLastRecoveryTime(userData.getLastRecoveryTime());
        player.sendPacket(ClientProtocol.U_ACTIVITY_PPL_SYNC_ENERGY, builder);
    }

    /**
     * 重新开始游戏
     */
    public void restartGame(int multiType) {
        userData.changeMulti(multiType);
        userData.setHeadColor(random.nextInt(PplMgr.TOTAL_COLOR_COUNT) + 1);
        userData.setCurColor(random.nextInt(PplMgr.TOTAL_COLOR_COUNT) + 1);
        userData.setCurMaxY(PplMgr.INIT_Y);
        userData.setPplLineList(new ArrayList<>());
        PplMgr.autoAddLine(userData, random);
        userData.saveMultiData();
    }

    /**
     * 游戏前检查一下maxY是否正确（出问题了影响坐标）
     */
    public void checkMaxY() {
        List<PplLine> pplLineList = userData.getPplLineList();
        userData.setCurMaxY(pplLineList.get(pplLineList.size() - 1).getY());
    }
}
